package com.benjaminwan.read.free.ui.gamepad

import android.app.Service
import android.content.res.Configuration
import android.os.Bundle
import android.os.VibrationEffect
import android.os.Vibrator
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
import com.benjaminwan.read.free.R
import com.benjaminwan.read.free.base.fragment.BaseFragment
import com.benjaminwan.read.free.base.viewmodel.state
import com.benjaminwan.read.free.databinding.FragmentGamepadBinding
import com.benjaminwan.read.free.ui.main.MainViewModel
import com.benjaminwan.read.free.ui.settings.SettingsViewModel
import com.benjaminwan.read.free.utils.RotationMode

class GamePadFragment : BaseFragment(), View.OnClickListener, View.OnTouchListener {

    private val mainVM by activityViewModel(MainViewModel::class)

    private val settingsVM by activityViewModel(SettingsViewModel::class)

    override var rotationMode: RotationMode = RotationMode.LANDSCAPE

    private val vibrator: Vibrator by lazy {
        requireContext().getSystemService(Service.VIBRATOR_SERVICE) as Vibrator
    }

    private val vibratorEnable: Boolean by lazy {
        settingsVM.state.vibratorEnable
    }

    private val vibrationEffect = VibrationEffect.createOneShot(
        100, VibrationEffect.DEFAULT_AMPLITUDE
    )

    private lateinit var binding: FragmentGamepadBinding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentGamepadBinding.inflate(layoutInflater)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initViews()
        if (vibratorEnable)
            vibrator.vibrate(vibrationEffect)
    }

    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        updateViews()
    }

    private fun updateViews() {
        val rootViewGroup = binding.root
        if (rootViewGroup is ViewGroup) {
            rootViewGroup.removeAllViews()
            View.inflate(requireContext(), R.layout.fragment_gamepad, rootViewGroup)
            initViews()
        }
    }

    private fun initViews() {
        binding.game1Btn.setOnTouchListener(this)
        binding.game2Btn.setOnTouchListener(this)
        binding.game3Btn.setOnTouchListener(this)
        binding.game4Btn.setOnTouchListener(this)
        binding.game5Btn.setOnTouchListener(this)
        binding.game6Btn.setOnTouchListener(this)
        binding.game7Btn.setOnTouchListener(this)
        binding.game8Btn.setOnTouchListener(this)
        binding.game1Btn.setOnClickListener(this)
        binding.game2Btn.setOnClickListener(this)
        binding.game3Btn.setOnClickListener(this)
        binding.game4Btn.setOnClickListener(this)
        binding.game5Btn.setOnClickListener(this)
        binding.game6Btn.setOnClickListener(this)
        binding.game7Btn.setOnClickListener(this)
        binding.game8Btn.setOnClickListener(this)
        binding.joystick.setOnMoveListener { angle, strength ->
            mainVM.gamePadAngleStrength(angle, strength)
        }
    }

    override fun onClick(view: View?) {
        view ?: return
        when (view.id) {
            else -> {
                if (vibratorEnable)
                    vibrator.vibrate(vibrationEffect)
            }
        }
    }

    override fun onTouch(view: View?, event: MotionEvent?): Boolean {
        view ?: return false
        event ?: return false
        when (view.id) {
            R.id.game1Btn, R.id.game2Btn, R.id.game3Btn, R.id.game4Btn,
            R.id.game5Btn, R.id.game6Btn, R.id.game7Btn, R.id.game8Btn -> {
                val which = view.tag.toString().toInt()
                when (event.action) {
                    MotionEvent.ACTION_DOWN -> mainVM.gamePadButtonDown(which)
                    MotionEvent.ACTION_UP -> mainVM.gamePadButtonUp(which)
                }
                return false
            }

            else -> {
                return false
            }
        }
    }

    override fun invalidate() = withState(mainVM) { main ->
        requireActivity().invalidateOptionsMenu()
    }

}